#include "FlvParser.h"
#include <string.h>
#include <assert.h>

#include <iostream>
#include <fstream>

#define CHECK_BUFFER(x) { if ((bufSize-offset) < (x)) { usedLength = offset; return 0; }}

int FlvParser::AudioTag::aacProfile;
int FlvParser::AudioTag::sampleRateIndex;
int FlvParser::AudioTag::channelConfig;

static const uint32_t h264StartCode = 0x01000000;

FlvParser::FlvParser()
{
    m_flvHeader = NULL;
    m_vjj = new Videojj();
}

FlvParser::~FlvParser()
{
    for (int i = 0; i < m_tagVector.size(); i++) {
        this->destroyTag(m_tagVector[i]);
        delete m_tagVector[i];
    }

    if (m_vjj != NULL)
        delete m_vjj;
}

int FlvParser::parse(uint8_t *pBuf, int bufSize, int &usedLength)
{
    int offset = 0;

    if (m_flvHeader == NULL) {
        CHECK_BUFFER(9);
        m_flvHeader = this->createFlvHeader(pBuf+offset);
        offset += m_flvHeader->headerSize;
    }

    while (1) {
        CHECK_BUFFER(15); //PrevSize(4字节) + Tag header(11字节)
        int prevSize = showU32(pBuf + offset);
        offset += 4;

        Tag *pTag = this->createTag(pBuf + offset, bufSize-offset);
        if (pTag == NULL) {
            offset -= 4;
            break;
        }
        offset += (11 + pTag->m_header.dataSize);

        m_tagVector.push_back(pTag);
    }

    usedLength = offset;
    return 0;
}

int FlvParser::printInfo()
{
    stat();

    std::cout << "vnum: " << m_stat.m_videoNum << " , anum: " << m_stat.m_audioNum << " ,mnum: " << m_stat.m_metaNum << std::endl;
    std::cout << "maxTimeStamp: " << m_stat.m_maxTimeStamp << " ,lengthSize: " << m_stat.m_lengthSize << std::endl;
    std::cout << "Vjj SEI num: " << m_vjj->m_vjjSEI.size() << std::endl;

    for (int i = 0; i < m_vjj->m_vjjSEI.size(); i++)
        std::cout << "SEI time: " << m_vjj->m_vjjSEI[i].timeStamp << std::endl;

    return 1;
}

int FlvParser::dumpH264(const std::string &path)
{
    std::fstream f;
    f.open(path.c_str(), std::ios_base::out | std::ios_base::binary);

    std::vector<Tag *>::iterator itTag;
    for (itTag = m_tagVector.begin(); itTag != m_tagVector.end(); itTag++) {
        if ((*itTag)->m_header.type != 0x09)
            continue;

        f.write((char *)(*itTag)->m_media, (*itTag)->m_mediaLength);
    }
    f.close();

    return 1;
}

int FlvParser::dumpAAC(const std::string &path)
{
    std::fstream f;
    f.open(path.c_str(), std::ios_base::out | std::ios_base::binary);

    std::vector<Tag *>::iterator itTag;
    for (itTag = m_tagVector.begin(); itTag != m_tagVector.end(); itTag++) {
        if ((*itTag)->m_header.type != 0x08)
            continue;

        AudioTag *pAudioTag = (AudioTag*)(*itTag);
        if (pAudioTag->soundFormat != 10)
            continue;

        if (pAudioTag->m_mediaLength != 0)
            f.write((char *)(*itTag)->m_media, (*itTag)->m_mediaLength);
    }

    f.close();

    return 1;
}

int FlvParser::dumpFlv(const std::string &path)
{
    std::fstream f;
    f.open(path.c_str(), std::ios_base::out | std::ios_base::binary);

    //write flv-header
    f.write((char *)m_flvHeader->pFlvHeader, m_flvHeader->headerSize);
    uint32_t lastTagSize = 0;

    //write flv-tag
    std::vector<Tag *>::iterator itTag;
    for (itTag = m_tagVector.begin(); itTag < m_tagVector.end(); itTag++) {
        uint32_t nn = writeU32(lastTagSize);
        f.write((char *)&nn, 4);

        //check duplicate start code
        if ((*itTag)->m_header.type == 0x09 && *((*itTag)->m_tagData + 1) == 0x01) {
            bool duplicate = false;
            uint8_t *pStartCode = (*itTag)->m_tagData + 5 + m_naluLength;
            unsigned naluLength = 0;
            uint8_t *pNaluLength = (uint8_t *)&naluLength;

            switch (m_naluLength) {
            case 4:
                naluLength = showU32((*itTag)->m_tagData + 5);
                break;
            case 3:
                naluLength = showU24((*itTag)->m_tagData + 5);
                break;
            case 2:
                naluLength = showU16((*itTag)->m_tagData + 5);
                break;
            default:
                naluLength = showU8((*itTag)->m_tagData + 5);
                break;
            }

            uint8_t *pStartCodeRecord = pStartCode;
            int i;
            for (i = 0; i < (*itTag)->m_header.dataSize - 5 - m_naluLength - 4; ++i) {
                if (pStartCode[i] == 0x00 && pStartCode[i+1] == 0x00 && pStartCode[i+2] == 0x00 &&
                        pStartCode[i+3] == 0x01) {
                    if (pStartCode[i+4] == 0x67) {
                        i += 4;
                        continue;
                    }
                    else if (pStartCode[i+4] == 0x68) {
                        i += 4;
                        continue;
                    }
                    else if (pStartCode[i+4] == 0x06) {
                        i += 4;
                        continue;
                    }
                    else {
                        i += 4;
                        duplicate = true;
                        break;
                    }
                }
            }

            if (duplicate) {
                naluLength -= i;
                (*itTag)->m_header.dataSize -= i;

                uint8_t *p = (uint8_t*)&((*itTag)->m_header.dataSize);
                (*itTag)->m_tagHeader[1] = p[2];
                (*itTag)->m_tagHeader[2] = p[1];
                (*itTag)->m_tagHeader[3] = p[0];

                f.write((char *)(*itTag)->m_tagHeader, 11);
                switch (m_naluLength) {
                case 4:
                    *((*itTag)->m_tagData + 5) = pNaluLength[3];
                    *((*itTag)->m_tagData + 6) = pNaluLength[2];
                    *((*itTag)->m_tagData + 7) = pNaluLength[1];
                    *((*itTag)->m_tagData + 8) = pNaluLength[0];
                    break;
                case 3:
                    *((*itTag)->m_tagData + 5) = pNaluLength[2];
                    *((*itTag)->m_tagData + 6) = pNaluLength[1];
                    *((*itTag)->m_tagData + 7) = pNaluLength[0];
                    break;
                case 2:
                    *((*itTag)->m_tagData + 5) = pNaluLength[1];
                    *((*itTag)->m_tagData + 6) = pNaluLength[0];
                    break;
                default:
                    *((*itTag)->m_tagData + 5) = pNaluLength[0];
                    break;
                }

                f.write((char *)(*itTag)->m_tagData, pStartCode - (*itTag)->m_tagData);
                f.write((char *)pStartCode + i, (*itTag)->m_header.dataSize - (pStartCode - (*itTag)->m_tagData));
            }
            else {
                f.write((char *)(*itTag)->m_tagHeader, 11);
                f.write((char *)(*itTag)->m_tagData, (*itTag)->m_header.dataSize);
            }
        }
        else {
            f.write((char *)(*itTag)->m_tagHeader, 11);
            f.write((char *)(*itTag)->m_tagData, (*itTag)->m_header.dataSize);
        }

        lastTagSize = 11 + (*itTag)->m_header.dataSize;
    }

    uint32_t nn = writeU32(lastTagSize);
    f.write((char *)&nn, 4);

    f.close();

    return 1;
}

uint32_t FlvParser::showU32(uint8_t *pBuf)
{
    return (pBuf[0] << 24) | (pBuf[1] << 16) | (pBuf[2] << 8) | pBuf[3];
}

uint32_t FlvParser::showU24(uint8_t *pBuf)
{
    return (pBuf[0] << 16) | (pBuf[1] << 8) | pBuf[2];
}

uint32_t FlvParser::showU16(uint8_t *pBuf)
{
    return (pBuf[0] << 8) | pBuf[1];
}

uint32_t FlvParser::showU8(uint8_t *pBuf)
{
    return pBuf[0];
}

void FlvParser::writeU64(uint64_t &x, int length, int value)
{
    uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - length);
    x = (x << length) | ((uint64_t)value & mask);
}

uint32_t FlvParser::writeU32(uint32_t n)
{
    uint32_t nn = 0;
    uint8_t *p = (uint8_t *)&n;
    uint8_t *pp = (uint8_t *)&nn;
    pp[0] = p[3];
    pp[1] = p[2];
    pp[2] = p[1];
    pp[3] = p[0];
    return nn;
}

FlvParser::FlvHeader *FlvParser::createFlvHeader(uint8_t *pBuf)
{
    FlvHeader *pHeader = new FlvHeader;
    pHeader->version = pBuf[3]; //版本号
    pHeader->haveAudio = (pBuf[4] >> 2) & 0x01; //是否有音频
    pHeader->haveVideo = (pBuf[4] >> 0) & 0x01; //是否有视频
    pHeader->headerSize = showU32(pBuf + 5);//头部长度

    pHeader->pFlvHeader = new uint8_t[pHeader->headerSize];
    memcpy(pHeader->pFlvHeader, pBuf, pHeader->headerSize);

    return pHeader;
}

FlvParser::Tag *FlvParser::createTag(uint8_t *pBuf, int leftLen)
{
    //开始解析标签头部
    TagHeader header;
    header.type = showU8(pBuf + 0);//类型
    header.dataSize = showU24(pBuf + 1);//标签 body 的长度
    header.timeStamp = showU24(pBuf + 4);//时间戳 低 24bits
    header.TSEx = showU8(pBuf + 7); //时间戳的扩展字段, 高 8bits
    header.streamID = showU24(pBuf + 8); //流的ID
    header.totalTS = (uint32_t)(header.TSEx << 24) + header.timeStamp;
    //标签头部解析结束

    if ((header.dataSize + 11) > leftLen)
        return NULL;

    Tag *pTag;
    switch (header.type) {
    case 0x09://视频类型的 tag
        pTag = new VideoTag(&header, pBuf, leftLen, this);
        break;
    case 0x08://音频类型的 tag
        pTag = new AudioTag(&header, pBuf, leftLen, this);
        break;
    case 0x12://script tag
        pTag = new MetaDataTag(&header, pBuf, leftLen, this);
        break;
    default://script 类型的 tag
        pTag = new Tag();
        pTag->init(&header, pBuf, leftLen);
        break;
    }

    return pTag;
}

int FlvParser::destroyTag(FlvParser::Tag *pTag)
{
    if (pTag->m_media != NULL)
        delete []pTag->m_media;
    if (pTag->m_tagData != NULL)
        delete []pTag->m_tagData;
    if (pTag->m_tagHeader != NULL)
        delete []pTag->m_tagHeader;
}

int FlvParser::stat()
{
    for (int i = 0; i < m_tagVector.size(); i++) {
        switch (m_tagVector[i]->m_header.type) {
        case 0x08:
            m_stat.m_audioNum++;
            break;
        case 0x09:
            statVideo(m_tagVector[i]);
            break;
        case 0x12:
            m_stat.m_metaNum++;
            break;
        default:
            break;
        }
    }

    return 1;
}

int FlvParser::statVideo(FlvParser::Tag *pTag)
{
    m_stat.m_videoNum++;
    m_stat.m_maxTimeStamp = pTag->m_header.timeStamp;

    if (pTag->m_tagData[0] == 0x17 && pTag->m_tagData[1] == 0x00)
        m_stat.m_lengthSize = (pTag->m_tagData[9] & 0x03) + 1;

    return 1;
}

int FlvParser::isUserDataTag(FlvParser::Tag *pTag)
{

}

/**
 * @brief 复制 header + body
 * @param pBuf
 * @param pHeader
 * @param leftLength
 */
void FlvParser::Tag::init(FlvParser::TagHeader *pHeader, uint8_t *pBuf, int leftLength)
{
    memcpy(&m_header, pHeader, sizeof(TagHeader));
    //复制标签头部信息 header
    m_tagHeader = new uint8_t[11];
    memcpy(m_tagHeader, pBuf, 11);
    //复制标签 body
    m_tagData = new uint8_t[m_header.dataSize];
    memcpy(m_tagData, pBuf + 11, m_header.dataSize);
}

/**
 * @brief VideoTag
 * @param pHeader
 * @param pBuf 整个 tag 的起始地址
 * @param leftLength
 * @param pParser
 */
FlvParser::VideoTag::VideoTag(FlvParser::TagHeader *pHeader, uint8_t *pBuf, int leftLength, FlvParser *pParser)
{
    //初始化
    init(pHeader, pBuf, leftLength);

    uint8_t *pd = m_tagData;
    frameType = (pd[0] & 0xf0) >> 4; //帧类型
    codecID = pd[0] & 0x0f;          //视频编码类型

    //开始解析
    if (m_header.type == 0x09 && codecID == 7)
        parseH264Tag(pParser);
}

int FlvParser::VideoTag::parseH264Tag(FlvParser *pParser)
{
    uint8_t *pd = m_tagData;
    /*
     * 数据包类型
     * 视频数据被压缩之后被打包成数据包在网上传输
     * 有两种类型的数据包：视频信息包(sps、pps等)和视频数据包(视频的压缩数据)
     */
    int AVCPAcketTpye = pd[1];
    int compositionTime = FlvParser::showU24(pd + 2);

    //如果是视频配置信息
    if (AVCPAcketTpye == 0) //AVC sequence header
        parseH264Configuration(pParser, pd);
    else if (AVCPAcketTpye == 1) //如果是视频数据
        parseNalu(pParser, pd);
    else
        std::cout << "AVCPacketType = " << AVCPAcketTpye << std::endl;

    return 1;
}

/**
 * @brief
AVCDecoderConfigurationRecord {
    uint32_t(8) configurationVersion = 1;  [0]
    uint32_t(8) AVCProfileIndication;       [1]
    uint32_t(8) profile_compatibility;      [2]
    uint32_t(8) AVCLevelIndication;         [3]
    bit(6) reserved = ‘111111’b;            [4]
    uint32_t(2) lengthSizeMinusOne;         [4] 计算方法是 1 + (lengthSizeMinusOne & 3)，实际计算结果一直是4
    bit(3) reserved = ‘111’b;                   [5]
    uint32_t(5) numOfSequenceParameterSets; [5] SPS 的个数，计算方法是 numOfSequenceParameterSets & 0x1F，实际计算结果一直为1
    for (i=0; i< numOfSequenceParameterSets; i++) {
        uint32_t(16) sequenceParameterSetLength ;   [6,7]
        bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;
    }
    uint32_t(8) numOfPictureParameterSets;      PPS 的个数，一直为1
    for (i=0; i< numOfPictureParameterSets; i++) {
        uint32_t(16) pictureParameterSetLength;
        bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
    }
}
 
_nNalUnitLength 这个变量告诉我们用几个字节来存储 NALU 的长度，如果 NALULengthSizeMinusOne 是 0，那么每个 NALU 使用一个字节
的前缀来指定长度，那么每个 NALU 包的最大长度是 255 字节，这个明显太小了，使用 2 个字节的前缀来指定长度，那么每个 NALU 包的最大长度是
64k 字节，也不一定够，一般分辨率为 1280 * 720 的图像编码出的 I 帧，可能大于 64k;3 字节是比较完美的，但是因为一些原因(例如对齐)没有被
广泛支持;因此 4 字节长度是目前使用最多的方式。
 * @param pParser
 * @param pTagData
 * @return 
 */
int FlvParser::VideoTag::parseH264Configuration(FlvParser *pParser, uint8_t *pTagData)
{
    uint8_t *pd = pTagData;
    //跨过 Tag data 的 VIDEODATA（1字节）AVCVIDEOPACKET(AVCPacketType(1字节) 和 CompositionTime(3字节) 4字节)
    //总共跨过 5 个字节

    //NalUint 长度表示占用的字节
    pParser->m_naluLength = (pd[9] & 0x03) + 1;//lengthSizeMinusOne 9 = 5 + 4

    int spsSize, ppsSize;
    //sps(序列参数集)的长度
    spsSize = FlvParser::showU16(pd + 11);//sequenceParameterSetLength 11 = 5 + 6

    //pps(图像参数集)的长度
    ppsSize = FlvParser::showU16(pd + 11 + (2 + spsSize) + 1);//pictureParameterSetLength

    //元数据的长度
    m_mediaLength = 4 + spsSize + 4 + ppsSize;//添加startCode
    m_media = new uint8_t[m_mediaLength];
    //保存元数据
    memcpy(m_media, &h264StartCode, 4);
    memcpy(m_media + 4, pd + 11 + 2, spsSize);
    memcpy(m_media + 4 + spsSize, &h264StartCode, 4);
    memcpy(m_media + 4 + spsSize + 4, pd + 11 + 2 + spsSize + 2 + 1, ppsSize);

    return 1;
}

int FlvParser::VideoTag::parseNalu(FlvParser *pParser, uint8_t *pTagData)
{
    uint8_t *pd = pTagData;
    int offset = 0;

    m_media = new uint8_t[m_header.dataSize + 10];
    m_mediaLength = 0;

    //跨过 Tag Data 的 VIDEODATA(1字节) AVCVIDEOPACKET(AVPacketType 和 ComposionTime 4 字节)
    offset = 5;//总共跨过 5 个字节 132 - 5 = 127 = m_naluLength(4字节) + NALU(123字节)
    //                                          startcode(4字节) + NALU(123字节) = 127

    while (1) {
        //如果解析完了一个 Tag，那么就跳出循环
        if (offset >= m_header.dataSize)
            break;

        //计算NALU(视频数据被包装成 NALU 在网上传输)的长度
        //一个 tag 可能包含多个 nalu，所以每个 nalu 前面有 NalUnitLength 字节表示每个 nalu 的长度
        int naluLength;
        switch (pParser->m_naluLength) {
        case 4:
            naluLength = FlvParser::showU32(pd + offset);
            break;
        case 3:
            naluLength = FlvParser::showU24(pd + offset);
            break;
        case 2:
            naluLength = FlvParser::showU16(pd + offset);
            break;
        default:
            naluLength = FlvParser::showU8(pd + offset);
            break;
        }

        //获取 NALU 的起始码
        memcpy(m_media + m_mediaLength, &h264StartCode, 4);
        //复制 NALU 的数据
        memcpy(m_media + m_mediaLength + 4, pd + offset + pParser->m_naluLength, naluLength);
        //解析NALU
        m_mediaLength += (4 + naluLength);
        offset += (pParser->m_naluLength + naluLength);
    }

    return 1;
}

FlvParser::AudioTag::AudioTag(FlvParser::TagHeader *pHeader, uint8_t *pBuf, int leftLength, FlvParser *pParser)
{
    init(pHeader, pBuf, leftLength);

    uint8_t *pd = m_tagData;
    soundFormat = (pd[0] & 0xf0) >> 4;//音频格式
    soundRate = (pd[0] & 0x0c) >> 2;  //采样率
    soundSize = (pd[0] & 0x02) >> 1;  //采样精度
    soundType = (pd[0] & 0x01);       //是否立体声

    if (soundFormat == 10)
        parseAACTag(pParser);
}

int FlvParser::AudioTag::parseAACTag(FlvParser *pParser)
{
    uint8_t *pd = m_tagData;
    //数据包类型:音频配置信息，音频数据
    int aacPacketType = pd[1];

    //如果是音频配置信息
    if (aacPacketType == 0)//AAC sequence header
        parseAudioSpecificConfig(pParser, pd);
    else if (aacPacketType == 1)//AAC RAW
        parseRawAAC(pParser, pd);
    else
        std::cout << "Other type: " << aacPacketType << std::endl;

    return 1;
}

int FlvParser::AudioTag::parseAudioSpecificConfig(FlvParser *pParser, uint8_t *pTagData)
{
    uint8_t *pd = m_tagData;

    aacProfile = ((pd[2] & 0xf8) >> 3);  //5bits aac 编码级别
    sampleRateIndex = ((pd[2] & 0x07) << 1) | (pd[3] >> 7);//4bits 真正的采样率索引
    channelConfig = (pd[3] >> 3) & 0x0f;                   //4bits 通道数量
    std::cout << "----- AAC -----" << std::endl;
    std::cout << "profile: " << aacProfile << std::endl;
    std::cout << "sample rate index: " << sampleRateIndex << std::endl;
    std::cout << "channel config: " << channelConfig << std::endl;

    m_media = NULL;
    m_mediaLength = 0;

    return 1;
}

int FlvParser::AudioTag::parseRawAAC(FlvParser *pParser, uint8_t *pTagData)
{
    uint64_t bits = 0;
    //数据长度 跳过 tag data 的第一个第二个字节
    int dataSize = m_header.dataSize - 2;//减去2字节的 audio tag data 信息部分

    //制作元数据
    writeU64(bits, 12, 0xFFF);
    writeU64(bits, 1, 0);
    writeU64(bits, 2, 0);
    writeU64(bits, 1, 1);
    writeU64(bits, 2, aacProfile - 1);
    writeU64(bits, 4, sampleRateIndex);
    writeU64(bits, 1, 0);
    writeU64(bits, 3, channelConfig);
    writeU64(bits, 1, 0);
    writeU64(bits, 1, 0);
    writeU64(bits, 1, 0);
    writeU64(bits, 1, 0);
    writeU64(bits, 13, 7 + dataSize);
    writeU64(bits, 11, 0x7FF);
    writeU64(bits, 2, 0);

    //writeU64 执行为上述的操作，最高的 8bits 还没有被移位到，实际是使用 7 个字节
    m_mediaLength = 7 + dataSize;
    m_media = new uint8_t[m_mediaLength];
    uint8_t p64[8];

    p64[0] = (uint8_t)(bits >> 56);//是 bits 的最高 8bits,实际为 0
    p64[1] = (uint8_t)(bits >> 48);//才是 ADTS 起始头，0xfff 的高 8bits
    p64[2] = (uint8_t)(bits >> 40);
    p64[3] = (uint8_t)(bits >> 32);
    p64[4] = (uint8_t)(bits >> 24);
    p64[5] = (uint8_t)(bits >> 16);
    p64[6] = (uint8_t)(bits >> 8);
    p64[7] = (uint8_t)(bits);

    memcpy(m_media, p64 + 1, 7);//ADTS header, p64 + 1 是从ADTS 起始头开始
    memcpy(m_media + 7, pTagData + 2, dataSize);//AAC body

    return 1;
}

FlvParser::MetaDataTag::MetaDataTag(FlvParser::TagHeader *pHeader, uint8_t *pBuf, int leftLength, FlvParser *pParser)
{
    init(pHeader, pBuf, leftLength);

    uint8_t *pd = m_tagData;
    m_amf1_type = showU8(pd+0);
    m_amf1_size = showU16(pd+1);

    if (m_amf1_type != 2) {
        std::cout << "no metadata." << std::endl;
        return;
    }

    //解析script
    if (strncmp((const char *)"onMetaData", (const char*)(pd + 3), 10) == 0)
        parseMeta(pParser);
}

double FlvParser::MetaDataTag::hexStr2double(const unsigned char *hex, const unsigned int length)
{
    double ret = 0;
    char hexstr[length * 2];
    memset(hexstr, 0, sizeof(hexstr));

    for (uint32_t i = 0; i < length; i++)
        sprintf(hexstr + i * 2, "%02x", hex[i]);

    sscanf(hexstr, "%llx", (unsigned long long*)&ret);

    return ret;
}

int FlvParser::MetaDataTag::parseMeta(FlvParser *pParser)
{
    uint8_t *pd = m_tagData;
    int dataSize = m_header.dataSize;

    uint32_t arrayLen = 0;
    uint32_t offset = 13;//Type + Value_Size + Value 占用13字节

    uint32_t nameLength = 0;
    double doubleValue = 0;
    std::string strValue = "";
    bool boolValue = false;
    uint32_t valueLen = 0;
    uint8_t u8Vlue = 0;

    if (pd[offset++] == 0x08) {//0x8 onMetaData
        arrayLen = showU32(pd+offset);
        offset += 4;
        std::cout << "ArrayLen = " << arrayLen << std::endl;
    }
    else {
        std::cout << "metaData format error." << std::endl;
        return -1;
    }

    for (uint32_t i = 0; i < arrayLen; i++) {
        doubleValue = 0;
        boolValue = false;
        strValue = "";
        //读取字段长度
        nameLength = showU16(pd+offset);
        offset += 2;//跳过2字节字段长度
        char name[nameLength + 1];//获取字段名称

        memset(name, 0, sizeof(name));
        memcpy(name, &pd[offset], nameLength);
        name[nameLength + 1] = '\0';
        offset += nameLength;//跳过字段名占用的长度

        uint8_t amfType = pd[offset++];
        switch (amfType) {
        case 0x0://Number type,就是 double 类型，占用 8 字节
            doubleValue = hexStr2double(&pd[offset], 8);
            offset += 8;//跳过 8 字节
            break;
        case 0x1://Boolean type,占用 1 字节
            u8Vlue = showU8(pd + offset);
            offset += 1;//跳过 1 字节
            if (u8Vlue != 0x00)
                boolValue = true;
            else
                boolValue = false;
            break;
        case 0x2://string type
            valueLen = showU16(pd + offset);
            offset += 2;//跳过 2 字节 length
            strValue.append(pd + offset, pd + offset + valueLen);
            strValue.append("");
            offset += valueLen;//跳过字段的值的长度
            break;
        default:
            std::cout << "un hangdle amfType: " << amfType << std::endl;
            break;
        }

        if (strncmp(name, "duration", 8) == 0)
            m_duration = doubleValue;
        else if (strncmp(name, "width", 5) == 0)
            m_width = doubleValue;
        else if (strncmp(name, "height", 6) == 0)
            m_height = doubleValue;
        else if (strncmp(name, "videodatarate", 13) == 0)
            m_videoDataRate = doubleValue;
        else if (strncmp(name, "framerate", 9) == 0)
            m_framRate = doubleValue;
        else if (strncmp(name, "videocodecid", 12) == 0)
            m_videoCodecID = doubleValue;
        else if (strncmp(name, "audiodatarate", 13) == 0)
            m_audioDataRate = doubleValue;
        else if (strncmp(name, "audiosamplerate", 15) == 0)
            m_audioSampleRate = doubleValue;
        else if (strncmp(name, "audiosamplesize", 15) == 0)
            m_audioSampleSize = doubleValue;
        else if (strncmp(name, "stereo", 6) == 0)
            m_stereo = boolValue;
        else if (strncmp(name, "audiocodecid", 12) == 0)
            m_audioCodecID = doubleValue;
        else if (strncmp(name, "major_brand", 11) == 0)
            m_majorBrand = strValue;
        else if (strncmp(name, "minor_version", 13) == 0)
            m_minorVersion = strValue;
        else if (strncmp(name, "compatible_brands", 17) == 0)
            m_compatibleBrands = strValue;
        else if (strncmp(name, "encoder", 7) == 0)
            m_encoder = strValue;
        else if (strncmp(name, "filesize", 8) == 0)
            m_filesSize = doubleValue;
    }

    printMeta();
    return 1;
}

void FlvParser::MetaDataTag::printMeta()
{
    printf("\nduration: %0.2lfs, filesize: %.0lfbytes\n", m_duration, m_filesSize);

    printf("width: %0.0lf, height: %0.0lf\n", m_width, m_height);
    printf("videodatarate: %0.2lfkbps, framerate: %0.0lffps\n", m_videoDataRate, m_framRate);
    printf("videocodecid: %0.0lf\n", m_videoCodecID);

    printf("audiodatarate: %0.2lfkbps, audiosamplerate: %0.0lfKhz\n",
           m_audioDataRate, m_audioSampleRate);
    printf("audiosamplesize: %0.0lfbit, stereo: %d\n", m_audioSampleSize, m_stereo);
    printf("audiocodecid: %0.0lf\n", m_audioCodecID);

    printf("major_brand: %s, minor_version: %s\n", m_majorBrand.c_str(), m_minorVersion.c_str());
    printf("compatible_brands: %s, encoder: %s\n\n", m_compatibleBrands.c_str(), m_encoder.c_str());
}
